package com.vdong.trade.order.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.vdong.interactive.course.facade.PeddleGoodsFacadeService;
import com.vdong.member.account.facade.AccountSystemUserFacadeService;
import com.vdong.trade.order.common.contract.OrderStateMachineEventModelContract;
import com.vdong.trade.order.common.contract.TableContract;
import com.vdong.trade.order.common.enums.TypeEnum;
import com.vdong.trade.order.common.exception.ProcessException;
import com.vdong.trade.order.entity.dto.param.*;
import com.vdong.trade.order.entity.dto.result.*;
import com.vdong.trade.order.entity.mo.*;
import com.vdong.trade.order.entity.po.CountOrderPO;
import com.vdong.trade.order.repository.OrderDisbRedundancyMORepository;
import com.vdong.trade.order.repository.OrderDisbSnapshotMORepository;
import com.vdong.trade.order.repository.OrderMORepository;
import com.vdong.trade.order.repository.SellHotMORepository;
import com.vdong.trade.order.service.OrderService;
import com.vdong.trade.trading.facade.enums.UserTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.lamb.framework.common.userDTO.AccountSystemUserInfoDTO;
import org.lamb.framework.common.util.*;
import org.lamb.framework.core.annotation.LambValid;
import org.lamb.framework.core.security.LambPrincipalFactoryContainer;
import org.lamb.framework.statemachine.handler.LambStateMachine;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import static com.vdong.trade.order.common.enums.ProcessExceptionEnum.*;

/**
 * @description: 主订单服务
 * @author: Mr.WangGang
 * @create: 2018-11-29 上午 11:18
 **/
@Service
@Slf4j
@com.alibaba.dubbo.config.annotation.Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private LambStateMachine lambStateMachine;

    @Resource
    private OrderMORepository orderMORepository;

    @Resource
    private SellHotMORepository sellHotMORepository;

    @Resource
    private OrderDisbRedundancyMORepository redundancy;

    @Resource
    private OrderDisbSnapshotMORepository snapshotMORepository;

    @Reference
    private PeddleGoodsFacadeService peddleGoodsFacadeService;

    @Reference
    private AccountSystemUserFacadeService accountSystemUserFacadeService;

    @Override
    @LambValid
    public OrderStateMachineResultDTO execute(@Valid @NotNull OrderStateMachineParamDTO param) {
        log.info("execute,入参为:[{}]", JSON.toJSONString(param));
        Object result = lambStateMachine.<String>execute(() -> {
            if (param.getEvent().startsWith(OrderStateMachineEventModelContract.DISB_ORDER_EVENT_MODEL))
                return Optional.ofNullable(orderMORepository.selectOrderByEntity(OrderMO.builder()
                        .orderNo(param.getOrderNo())
                        .status(TableContract.Order.status.EFFECTIVE).build()))
                        .orElseThrow(() -> new ProcessException(EB00000000)).getOrderStatus();
            throw new ProcessException(EB00000100);
        }, param.getEvent(), param.getData());
        return OrderStateMachineResultDTO.builder().alternativeData(result).event(param.getEvent()).build();
    }

    @Override
    public List<ChannelCurveResultDTO> channelCurve(ChannelCurveParamDTO param) {
        log.info("channelCurve,入参为:[{}]", JSON.toJSONString(param));
        if (StringUtil.hasBlank(param.getStartDate(), param.getEndDate())) {
            param.setEndDate(DateUtil.getDateToStr(new Date()));
        }
        AccountSystemUserInfoDTO accountSystemUser = LambPrincipalFactoryContainer.getAccountSystemUser();
        param.setUserId(accountSystemUser.getSysUserId());
        return CopyUtil.copyList(Optional.ofNullable(orderMORepository.channelCurve(param))
                .orElseThrow(() -> new ProcessException(EB00000005)), ChannelCurveResultDTO.class);
    }

    @Override
    public PageInfo<DistributionOrdersResultDTO> DistributionOrderList(DistributionOrdersParamDTO param) {
        log.info("DistributionOrderList,入参为:[{}]", JSON.toJSONString(param));
        if (!StringUtil.hasBlank(param.getDate())) {
            param.setDate(DateUtil.stampToDate(param.getDate()));
        }
        PageInfo<DistributionOrdersResultDTO> resultPageInfo = PageHelper.startPage(param.getPageNum(), param.getPageSize())
                .doSelectPageInfo(() -> {
                    CopyUtil.copyList
                            (Optional.ofNullable(orderMORepository.distributionOrderList(param))
                                    .orElseThrow(() -> new ProcessException(EB00000005)), DistributionOrdersResultDTO.class);
                });
        log.info("获取到的分页总条数是:[{}]", resultPageInfo.getTotal());
        return resultPageInfo;
    }

    @Override
    public DistributionOrderDetailResultDTO DistributionOrderDetail(DistributionOrdersParamDTO param) {
        log.info("DistributionOrderDetail,入参为:[{}]", JSON.toJSONString(param));
        return CopyUtil.copyObject(Optional.ofNullable(orderMORepository.distributionOrderDetail(param))
                .orElseThrow(() -> new ProcessException(EB00000012)), new DistributionOrderDetailResultDTO());
    }

    @Override
    public PageInfo<DetailEarningListResultDTO> DetailEarningList(DistributionOrdersParamDTO param) {
        log.info("DetailEarningList,入参为:[{}]", JSON.toJSONString(param));
        return PageHelper.startPage(param.getPageNum(), param.getPageSize())
                .doSelectPageInfo(() -> {
                    CopyUtil.copyList
                            (Optional.ofNullable(orderMORepository.DetailEarningList(param))
                                    .orElseThrow(() -> new ProcessException(EB00000005)), DetailEarningListResultDTO.class);
                });
    }

    @Override
    public DetailEarningDetailDTO DetailEarningDetail(DistributionOrdersParamDTO param) {
        log.info("DetailEarningDetail,入参为:[{}]", JSON.toJSONString(param));
        DistributionOrderDetailMO mo = orderMORepository.distributionOrderDetail(param);
        if (StringUtil.hasBlank(mo)) throw new ProcessException(EB00000012);
        String basePeddleGoodsDetail = peddleGoodsFacadeService.getBasePeddleGoodsDetail
                (JSON.toJSONString(PeddleUserParamDTO.builder().peddleGoodsId(Long.valueOf(mo.getProductKey())).build()));
        if (StringUtil.hasBlank(basePeddleGoodsDetail)) throw new ProcessException(EB00000003);
        BasePeddleGoodsDTO disbProduct = FacadeResultUtils.stringToFacadeBean(basePeddleGoodsDetail,
                BasePeddleGoodsDTO.class).getData();
        DetailEarningDetailDTO build = DetailEarningDetailDTO.builder().orderNo(mo.getOrderNo())
                .createTime(mo.getCreateTime()).orderType(mo.getOrderType())
                .orderAmount(mo.getOrderAmount()).orderStatus(mo.getOrderStatus())
                .buyerWxName(mo.getBuyerWxName()).pusherWxName(mo.getPusherWxName())
                .pusherCommissionRate(mo.getPusherCommissionRate())
                .pusherAnticipatedIncomeAmount(mo.getPusherAnticipatedIncomeAmount())
                .platformExtractionRate(mo.getPlatformExtractionRate())
                .platformAnticipatedIncomeAmount(mo.getPlatformAnticipatedIncomeAmount())
                .phone(mo.getPhone()).source("店铺发布").authorName(disbProduct.getAuthorName())
                .payChannel("微信支付").wechatNo("").productName(disbProduct.getGoodsName()).productType("付费课程")
                .productDistributionAmount(mo.getProductDistributionAmount()).build();
        return build;
    }

    @Override
    public CountOrderResultDTO countOrder(CountOrderPO param) {
        log.info("countOrder,入参为:[{}]", JSON.toJSONString(param));
        AccountSystemUserInfoDTO accountSystemUser = LambPrincipalFactoryContainer.getAccountSystemUser();
        if (StringUtil.hasBlank(accountSystemUser)) {
            throw new ProcessException(EB00000012);
        } else {
            param.setUserId(accountSystemUser.getSysUserId());
        }
        return BeanPlasticityUtill.copy(CountOrderResultDTO.class,
                Optional.ofNullable(orderMORepository.countOrder(param))
                        .orElseThrow(() -> new ProcessException(EB00000012)));
    }

    @Override
    public PageInfo<PeddleDistributionListResultDTO> peddleDistributionOrderList(DistributionOrdersParamDTO param) {
        log.info("peddleDistributionOrderList,入参为:[{}]", JSON.toJSONString(param));
        PageMethod.startPage(param.getPageNum(), param.getPageSize());
        OrderDisbSnapshotMO build = OrderDisbSnapshotMO.builder().pusherKey(Long.valueOf(param.getUserId())).build();
        List<PusherOrderListMO> pusherOrderListMOS = snapshotMORepository.pusherOrderListMO(build);
        List<PeddleDistributionListResultDTO> list = new ArrayList<>();
        for (PusherOrderListMO push : pusherOrderListMOS) {
            String basePeddleGoodsDetail = null;
            try {
                basePeddleGoodsDetail = peddleGoodsFacadeService.getBasePeddleGoodsDetail
                        (JSON.toJSONString(PeddleUserParamDTO.builder().peddleGoodsId(push.getProductKey()).build()));
            } catch (Exception e) {
                log.error("peddleDistributionOrderList接口调用peddleGoodsFacadeService.getBasePeddleGoodsDetail异常:", e);
            }

            if (StringUtil.hasBlank(basePeddleGoodsDetail)) throw new ProcessException(EB00000003);
            BasePeddleGoodsDTO disbProduct = FacadeResultUtils.stringToFacadeBean(basePeddleGoodsDetail,
                    BasePeddleGoodsDTO.class).getData();
            String status = Integer.valueOf(push.getOrderStatus()) == 10 ? "1" : "0";
            list.add(PeddleDistributionListResultDTO
                    .builder().imageUrl(disbProduct.getImageUrl())
                    .goodsName(disbProduct.getGoodsName())
                    .price(String.valueOf(disbProduct.getPrice()))
                    .settlementStatus(status)
                    .pusherCommissionRate(String.valueOf(push.getPusherCommissionRate()))
                    .pusherAnticipatedIncomeAmount(String.valueOf(push.getPusherAnticipatedIncomeAmount())).build());
        }
        return new PageInfo<>(list);
    }

    @Override
    public PageInfo<DetailEarningListResultDTO> transactionList(DistributionOrdersParamDTO param) {
        log.info("transactionList,入参为:[{}]", JSON.toJSONString(param));
        PageInfo<DetailEarningListResultDTO> resultPageInfo = PageHelper.startPage(param.getPageNum(), param.getPageSize())
                .doSelectPageInfo(() -> {
                    CopyUtil.copyList
                            (Optional.ofNullable(orderMORepository.transactionList(param))
                                    .orElseThrow(() -> new ProcessException(EB00000005)), DetailEarningListResultDTO.class);
                });
        return resultPageInfo;
    }

    @Override
    public TransactionDetailResultDTO transactionDetail(DistributionOrdersParamDTO param) {
        log.info("transactionDetail,入参为:[{}]", JSON.toJSONString(param));
        TransactionDetailMO mo = orderMORepository.transactionDetail(param);
        if (StringUtil.hasBlank(mo)) throw new ProcessException(EB00000012);
        String basePeddleGoodsDetail = peddleGoodsFacadeService.getBasePeddleGoodsDetail
                (JSON.toJSONString(PeddleUserParamDTO.builder().peddleGoodsId(mo.getProductKey()).build()));
        if (StringUtil.hasBlank(basePeddleGoodsDetail)) throw new ProcessException(EB00000003);
        BasePeddleGoodsDTO disbProduct = FacadeResultUtils.stringToFacadeBean(basePeddleGoodsDetail,
                BasePeddleGoodsDTO.class).getData();
        TransactionDetailResultDTO build = TransactionDetailResultDTO.builder()
                .createTime(mo.getCreateTime()).orderType(mo.getOrderType())
                .orderAmount(mo.getOrderAmount()).productName(disbProduct.getGoodsName())
                .productType("1").source("店铺发布").authorName(disbProduct.getAuthorName()).build();
        return build;
    }

    @Override
    public PageInfo<SellHotResultDTO> sellHot(DistributionOrdersParamDTO param) {
        log.info("transactionDetail,入参为:[{}]", JSON.toJSONString(param));
        PageMethod.startPage(param.getPageNum(), param.getPageSize());
        if (param.getType().compareTo(TypeEnum.WEEK.getValue()) == 0) {
            param.setStartTime(DateUtil.getThisWeekMonday(new Date()));
            param.setEndTime(DateUtil.getThisWeekSunday(new Date()));
        }
        if (param.getType().compareTo(TypeEnum.MONTH.getValue()) == 0) {
            param.setStartTime(DateUtil.getFirstDayByMonth(DateUtil.getYearAndMonth()));
            param.setEndTime(DateUtil.getLastDayByMonth(DateUtil.getYearAndMonth()));
        }
        return new PageInfo<>(CopyUtil.copyList(sellHotMORepository.selectByParam(param), SellHotResultDTO.class));
    }

    @Override
    public PageInfo<PeddleIncomeFormDTO> pusherEarnings(DistributionOrdersParamDTO param) throws Exception {
        log.info("pusherEarnings,入参为:[{}]", JSON.toJSONString(param));
        if (StringUtil.hasBlank(param.getUserId(), param.getPageNum(), param.getPageSize()))
            throw new ProcessException(EB00000008);
        PageMethod.startPage(param.getPageNum(), param.getPageSize());
        List<SillysoftResultMO> list = orderMORepository.selectSillysoft
                (ChannelCurveParamDTO.builder().pusherKey(String.valueOf(param.getUserId())).build());
        if (list.size() < 1) return new PageInfo<>();
        List<PeddleIncomeFormDTO> result = new ArrayList<>();
        for (SillysoftResultMO resultDTO : list) {
            String basePeddleGoodsDetail = peddleGoodsFacadeService.getBasePeddleGoodsDetail
                    (JSON.toJSONString(PeddleUserParamDTO.builder()
                            .peddleGoodsId(Long.valueOf(resultDTO.getProductKey())).build()));
            if (StringUtil.hasBlank(basePeddleGoodsDetail)) throw new ProcessException(EB00000003);
            BasePeddleGoodsDTO disbProduct = FacadeResultUtils.stringToFacadeBean(basePeddleGoodsDetail,
                    BasePeddleGoodsDTO.class).getData();
            //获取商户
            String merchantUser = accountSystemUserFacadeService.getAccountSystemPeddleUserInfoBySysUserId
                    (JSON.toJSONString(ChannelCurveParamDTO.builder().sysUserId(disbProduct.getSysUserId())
                            .userType(UserTypeEnum.MERCHANT.getValue().toString()).build()));
            if (StringUtil.hasBlank(merchantUser)) throw new ProcessException(EB00000012);
            MerchantSaasSysUserInfoDTO merchantDTO = FacadeResultUtils.
                    stringToFacadeBean(merchantUser, MerchantSaasSysUserInfoDTO.class).getData();

            result.add(PeddleIncomeFormDTO.builder().peddleGoodsId(disbProduct.getPeddleGoodsId().toString())
                    .peddleGoodsName(disbProduct.getGoodsName()).imageUrl(disbProduct.getImageUrl())
                    .systemUserName(merchantDTO.getSysUserName()).categoryId(disbProduct.getCategoryId().toString())
                    .categoryName(disbProduct.getCategoryName()).typeId(disbProduct.getTypeId().toString())
                    .typeName(disbProduct.getTypeName()).classifyType(disbProduct.getClassifyType().toString())
                    .income(resultDTO.getEarning()).build());
        }
        return new PageInfo<>(result);
    }
}
